﻿#ifndef __GEOMETRY_H__
#define __GEOMETRY_H__

#include <cmath>
#include <vector>
#include <ostream>
#include "tgaimage.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template <typename T>
class Vec4;
template <typename T>
class Vec3;
template <typename T>
class Vec2;

template <class t> struct Vec2 {
	union {
		struct {t u, v;};
		struct {t x, y;};
		t raw[2];
	};
	Vec2() : u(0), v(0) {}
	Vec2(t _u, t _v) : u(_u),v(_v) {}
	inline Vec2<t> operator +(const Vec2<t> &V) const { return Vec2<t>(u+V.u, v+V.v); }
	inline Vec2<t> operator -(const Vec2<t> &V) const { return Vec2<t>(u-V.u, v-V.v); }
	inline Vec2<t> operator -() const { return Vec2<t>(-x, -y); }
	inline Vec2<t> operator *(float f)          const { return Vec2<t>(u*f, v*f); }
	inline Vec2<t> operator /(float f)          const { return Vec2<t>(u/f, v/f); }
	template <class > friend std::ostream& operator<<(std::ostream& s, Vec2<t>& v);
	// 新增模板构造函数：允许从其他类型的 Vec2 转换
	template <typename U>
	Vec2(const Vec2<U>& other): u(static_cast<t>(other.u)), v(static_cast<t>(other.v)) {}
	// 新增数组下标访问
	t& operator[](size_t i) { return raw[i]; }
	const t& operator[](size_t i) const { return raw[i]; }
	// 新增标准化函数
    Vec2<t> normalized() const 
	{
		t len = std::sqrt(x * x + y * y);
		if (len == 0) 
		{
			return Vec2<t>(0, 0);
		}
		return (*this) * (1 / len);
	}
};

template <class t> struct Vec3 {
	union {
		struct {t x, y, z;};
		struct { t ivert, iuv, inorm; };
		t raw[3];
	};
	Vec3() : x(0), y(0), z(0) {}
	Vec3(t _x, t _y, t _z) : x(_x),y(_y),z(_z) {}
	inline Vec3<t> operator ^(const Vec3<t> &v) const { return Vec3<t>(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); } // 叉积
	inline Vec3<t> cross(const Vec3<t>& v) const { return Vec3<t>(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }// 叉积
	inline Vec3<t> operator +(const Vec3<t> &v) const { return Vec3<t>(x+v.x, y+v.y, z+v.z); }
	inline Vec3<t> operator +(float v) const { return Vec3<t>(x + v, y + v, z + v); }
	inline Vec3<t> operator -(const Vec3<t> &v) const { return Vec3<t>(x-v.x, y-v.y, z-v.z); }
	inline Vec3<t> operator *(float f)          const { return Vec3<t>(x*f, y*f, z*f); }
    inline Vec3<t> operator /(float f)          const { return Vec3<t>(x/f, y/f, z/f); }
	inline t       operator *(const Vec3<t> &v) const { return x*v.x + y*v.y + z*v.z; } // 点积
	inline t       dot(const Vec3<t>& v) const { return x * v.x + y * v.y + z * v.z; } // 点积
	float norm () const { return std::sqrt(x*x+y*y+z*z); }
	Vec3<t> & normalize(t l=1) { *this = (*this)*(l/norm()); return *this; }
	template <class > friend std::ostream& operator<<(std::ostream& s, Vec3<t>& v);
	// 新增模板构造函数：允许从其他类型的 Vec3 转换
	template <typename U>
	Vec3(const Vec3<U>& other): x(static_cast<t>(other.x)), y(static_cast<t>(other.y)), z(static_cast<t>(other.z)) {}
	// 允许从 Vec4 向 Vec3 转换
	template <typename U>
	Vec3(const Vec4<U>& other) : x(static_cast<t>(other.x)), y(static_cast<t>(other.y)), z(static_cast<t>(other.z)) {}
	Vec3(const TGAColor& color) : x(color.r / 255.0f * 2 - 1), y(color.g / 255.0f * 2 - 1), z(color.b / 255.0f * 2 - 1) {}
	// 新增数组下标访问
	t& operator[](size_t i) { return raw[i]; }
	const t& operator[](size_t i) const { return raw[i]; }
	// 新增标准化函数
    Vec3<t> normalized() const 
	{
		t len = norm();
		if (len == 0) 
		{
			return Vec3<t>(0, 0, 0);
		}
		return (*this) * (1 / len);
	}
	inline Vec3<t> operator-() const { return Vec3<t>(-x, -y, -z); }
    Vec3<t> Multi(const Vec3<t>& other) const
    {
		return Vec3<t>(x * other.x, y * other.y, z * other.z);
    }
};

template <class T>
struct Vec4 {
	union {
		struct { T x, y, z, w; };
		struct { T r, g, b, a; }; // 可选颜色别名
		T raw[4];
	};

	// 构造函数
	Vec4() : x(0), y(0), z(0), w(0) {}
	Vec4(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) {}
    Vec4(const Vec3<T>& v, T _w) : x(v.x), y(v.y), z(v.z), w(_w) {}

	// 基础运算
	inline Vec4<T> operator+ (const Vec4<T>& v) const {
		return Vec4<T>(x + v.x, y + v.y, z + v.z, w + v.w);
	}

	inline Vec4<T> operator- (const Vec4<T>& v) const {
		return Vec4<T>(x - v.x, y - v.y, z - v.z, w - v.w);
	}

	inline Vec4<T> operator-() const { return Vec4<T>(-x, -y, -z, -w); }

	inline Vec4<T> operator* (float f) const {
		return Vec4<T>(x * f, y * f, z * f, w * f);
	}
	inline Vec4<T> operator/ (float f) const {
        if (f == 0) return *this;
		return Vec4<T>(x / f, y / f, z / f, w / f);
	}

	// 四维点积
	inline T operator* (const Vec4<T>& v) const {
		return x * v.x + y * v.y + z * v.z + w * v.w;
	}

	// 模长计算
	float norm() const {
		return std::sqrt(x * x + y * y + z * z + w * w);
	}

	// 归一化
	Vec4<T>& normalize(T l = 1) {
		float len = norm();
		if (len != 0) *this = (*this) * (l / len);
		return *this;
	}

	Vec4<T> normalized() const {
		float len = norm();
		return (len != 0) ? (*this) * (1.0f / len) : Vec4<T>();
	}

	// 类型转换构造函数
	template <typename U>
	explicit Vec4(const Vec4<U>& other) :
		x(static_cast<T>(other.x)),
		y(static_cast<T>(other.y)),
		z(static_cast<T>(other.z)),
		w(static_cast<T>(other.w)) {
	}

	// 下标访问
	T& operator[](size_t i) { return raw[i]; }
	const T& operator[](size_t i) const { return raw[i]; }

	template <class > friend std::ostream& operator<<(std::ostream& s, Vec3<T>& v);
};

typedef Vec2<float> Vec2f;
typedef Vec2<int>   Vec2i;
typedef Vec3<float> Vec3f;
typedef Vec3<int>   Vec3i;
typedef Vec4<float> Vec4f;
typedef Vec4<int>   Vec4i;

template <class t> std::ostream& operator<<(std::ostream& s, Vec2<t>& v) {
	s << "(" << v.x << ", " << v.y << ")\n";
	return s;
}

template <class t> std::ostream& operator<<(std::ostream& s, Vec3<t>& v) {
	s << "(" << v.x << ", " << v.y << ", " << v.z << ")\n";
	return s;
}

template <class t> std::ostream& operator<<(std::ostream& s, Vec4<t>& v) {
	s << "(" << v.x << ", " << v.y << ", " << v.z << ", " << v.w << ")\n";
	return s;
}

template <class t> Vec3<t> operator*(float f, const Vec3<t>& v)
{
    return Vec3<t>(v.x * f, v.y * f, v.z * f);
}
template <class t> Vec2<t> operator*(float f, const Vec2<t>& v)
{
	return Vec2<t>(v.x * f, v.y * f);
}
template <class t> Vec4<t> operator*(float f, const Vec4<t>& v)
{
	return Vec4<t>(v.x * f, v.y * f, v.z * f, v.w * f);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename T>
bool IsNearlyEqual(T a, T b)
{
	// 处理完全相等的情况，避免除以 0
	if (a == b)
	{
		return true;
	}
	T absA = std::abs(a);
	T absB = std::abs(b);
	T diff = std::abs(a - b);
	// 绝对误差 <= 相对误差
	T epsilon = std::numeric_limits<T>::epsilon();
	T relativeError = std::max(absA, absB) * epsilon;
	return diff <= relativeError;
}

template <typename T, typename U>
bool IsNearlyEqual(T a, U b)
{
	using CommonType = std::common_type_t<T, U>;
	return IsNearlyEqual(static_cast<CommonType>(a), static_cast<CommonType>(b));
}

template <typename T>
bool IsNearlyZero(T a)
{
	if (a == 0)
	{
		return true;
	}
	T absA = std::abs(a);
	T epsilon = std::numeric_limits<T>::epsilon();
	T relativeError = absA * epsilon;
	return std::abs(a) <= relativeError;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif //__GEOMETRY_H__
